/**
 * Printing helpers that prioritize LODOP.
 * Only A5 (portrait) and 80 mm thermal paper are supported for now.
 */

export interface PrintConfig {
  /** HTML string or DOM element that needs to be printed */
  content: string | HTMLElement;
  /** Optional print window title */
  title?: string;
  /** Style configuration */
  styles?: {
    /** Paper size, only A5 and A80 are handled */
    pageSize?: 'A5' | 'A80';
    /** Page margin */
    margin?: string;
    /** Content padding inside the printable area */
    contentPadding?: string;
    /** Custom content width */
    contentWidth?: string;
    /** Custom content height */
    contentHeight?: string;
    /** Extra CSS */
    customStyles?: string;
  };
  /** Printer configuration */
  printer?: {
    /** Manual printer index (0-based), if specified, auto-selection will be skipped */
    index?: number;
    /** Disable auto printer selection by paper size */
    disableAutoSelect?: boolean;
  };
  onBeforePrint?: () => void;
  onAfterPrint?: () => void;
  /** Delay (ms) before removing helper iframe when falling back to browser print */
  removeDelay?: number;
}

export const PAPER_SIZES = {
  A5: { width: '148mm', height: '210mm', name: 'A5' },
  A80: { width: '80mm', height: 'auto', name: 'A80' },
} as const;

type PaperSizeKey = keyof typeof PAPER_SIZES;
const DEFAULT_PAGE_SIZE: PaperSizeKey = 'A5';

const PAGE_STYLE_PRESETS: Record<
  PaperSizeKey,
  { margin: string; padding: string }
> = {
  A5: { margin: '8mm 2mm 8mm 2mm', padding: '2mm' },
  A80: { margin: '3mm 0mm 3mm 0mm', padding: '2mm' },
};

declare global {
  interface Window {
    getCLodop?: () => LodopInstance;
    CLODOP?: LodopInstance;
  }
}

type LodopInstance = {
  PRINT_INIT: (title: string) => void;
  ADD_PRINT_HTM: (
    top: string | number,
    left: string | number,
    width: string | number,
    height: string | number,
    html: string
  ) => void;
  SET_PRINT_PAGESIZE: (
    orient: number,
    width: string | number,
    height: string | number,
    pageName?: string
  ) => void;
  SET_PRINT_MODE?: (modeName: string, value: any) => void;
  SET_PRINTER_INDEX?: (index: number) => void;
  GET_PRINTER_COUNT?: () => number;
  GET_PRINTER_NAME?: (index: number) => string;
  GET_PAGESIZES_COUNT?: (printerIndex: number) => number;
  GET_PAGESIZES_NAME?: (printerIndex: number, pageIndex: number) => string;
  GET_PAGESIZES_WIDTH?: (printerIndex: number, pageIndex: number) => number;
  GET_PAGESIZES_HEIGHT?: (printerIndex: number, pageIndex: number) => number;
  PREVIEW?: () => boolean;
  PRINT?: () => boolean;
  [key: string]: any;
};

interface ResolvedStyleOptions {
  pageSize: PaperSizeKey;
  margin: string;
  customStyles: string;
  resolvedPadding: string;
  resolvedWidth?: string;
  resolvedHeight?: string;
}

interface GeneratedStyleResult {
  css: string;
  options: ResolvedStyleOptions;
}

const convertSizeToLodopValue = (size?: string | number): number => {
  if (size === undefined || size === null) return 0;
  if (typeof size === 'number') return size;

  const normalized = size.trim().toLowerCase();
  if (!normalized || normalized === 'auto') return 0;

  const mmMatch = normalized.match(/^(\d+(?:\.\d+)?)mm$/);
  if (mmMatch) {
    return Math.round(parseFloat(mmMatch[1] || '0') * 10);
  }

  const cmMatch = normalized.match(/^(\d+(?:\.\d+)?)cm$/);
  if (cmMatch) {
    return Math.round(parseFloat(cmMatch[1] || '0') * 100);
  }

  const inchMatch = normalized.match(/^(\d+(?:\.\d+)?)in(ch|ches)?$/);
  if (inchMatch) {
    return Math.round(parseFloat(inchMatch[1] || '0') * 254);
  }

  const pxMatch = normalized.match(/^(\d+(?:\.\d+)?)px$/);
  if (pxMatch) {
    const pxValue = parseFloat(pxMatch[1] || '0');
    return Math.round((pxValue * 254) / 96);
  }

  const numericValue = Number(normalized);
  return Number.isFinite(numericValue) ? numericValue : 0;
};

interface MarginValues {
  top: string;
  right: string;
  bottom: string;
  left: string;
}

const parseMarginValues = (margin?: string): MarginValues => {
  const defaultValue = '0mm';
  if (!margin) {
    return {
      top: defaultValue,
      right: defaultValue,
      bottom: defaultValue,
      left: defaultValue,
    };
  }

  const normalized = margin
    .split(/\s+/)
    .map((value) => value.trim())
    .filter(Boolean);

  const normalizeValue = (value?: string): string => {
    if (!value || value.toLowerCase() === 'auto') {
      return defaultValue;
    }
    return value === '0' ? defaultValue : value;
  };

  const [top, right, bottom, left] = (() => {
    switch (normalized.length) {
      case 1:
        return [normalized[0], normalized[0], normalized[0], normalized[0]];
      case 2:
        return [normalized[0], normalized[1], normalized[0], normalized[1]];
      case 3:
        return [normalized[0], normalized[1], normalized[2], normalized[1]];
      default:
        return [
          normalized[0],
          normalized[1],
          normalized[2],
          normalized[3] ?? normalized[1],
        ];
    }
  })();

  return {
    top: normalizeValue(top),
    right: normalizeValue(right),
    bottom: normalizeValue(bottom),
    left: normalizeValue(left),
  };
};

const convertToMillimeter = (value?: string | number): number => {
  const result = convertSizeToLodopValue(value);
  return result ? result / 10 : 0;
};

const getPrimaryLengthValue = (value?: string): string | undefined => {
  if (!value) return undefined;
  const normalized = value.trim();
  if (!normalized) return undefined;
  const [first] = normalized.split(/\s+/);
  return first;
};

const computeSafeContentWidth = (
  pageWidth?: string,
  margin?: string,
  padding?: string
): string | undefined => {
  if (!pageWidth) return undefined;
  const pageWidthMm = convertToMillimeter(pageWidth);
  if (!pageWidthMm) return undefined;

  const resolvedMargin = parseMarginValues(margin);
  const leftMm = convertToMillimeter(resolvedMargin.left);
  const rightMm = convertToMillimeter(resolvedMargin.right);
  const paddingValue = getPrimaryLengthValue(padding);
  const paddingMm = paddingValue ? convertToMillimeter(paddingValue) : 0;

  const safeWidth = pageWidthMm - leftMm - rightMm - paddingMm * 2;
  if (safeWidth <= 0) return undefined;
  const normalized = Math.max(10, safeWidth);
  return `${Math.round(normalized * 10) / 10}mm`;
};

const resolveStyleOptions = (config: PrintConfig): ResolvedStyleOptions => {
  const {
    pageSize,
    margin,
    contentPadding,
    contentWidth,
    contentHeight,
    customStyles = '',
  } = config.styles || {};

  const pageSizeName =
    typeof pageSize === 'string' ? pageSize.toUpperCase() : undefined;

  const effectivePageSize: PaperSizeKey =
    pageSizeName && pageSizeName in PAPER_SIZES
      ? (pageSizeName as PaperSizeKey)
      : DEFAULT_PAGE_SIZE;

  const presetSize = PAPER_SIZES[effectivePageSize];
  const presetStyles = PAGE_STYLE_PRESETS[effectivePageSize];
  const resolvedMargin = margin ?? presetStyles.margin;
  const resolvedPadding = contentPadding ?? presetStyles.padding;

  const resolvedWidth =
    contentWidth ??
    computeSafeContentWidth(
      presetSize.width,
      resolvedMargin,
      resolvedPadding
    ) ??
    presetSize.width;

  const resolvedHeight = contentHeight ?? presetSize.height;

  return {
    pageSize: effectivePageSize,
    margin: resolvedMargin,
    customStyles,
    resolvedPadding,
    resolvedWidth,
    resolvedHeight,
  };
};

const generatePrintStyles = (config: PrintConfig): GeneratedStyleResult => {
  const options = resolveStyleOptions(config);
  const { resolvedWidth, resolvedHeight, resolvedPadding } = options;

  const css =
    options.pageSize === 'A80'
      ? buildThermalStyles(options, resolvedPadding)
      : buildA5Styles(options, resolvedWidth, resolvedHeight, resolvedPadding);

  return { css, options };
};

const buildA5Styles = (
  options: ResolvedStyleOptions,
  resolvedWidth: string | undefined,
  resolvedHeight: string | undefined,
  resolvedPadding: string
): string => {
  const bodyHeightStyles =
    resolvedHeight && resolvedHeight !== 'auto'
      ? `min-height: ${resolvedHeight};`
      : '';

  const wrapperWidthStyles =
    resolvedWidth && resolvedWidth !== 'auto'
      ? `
      width: ${resolvedWidth};
      max-width: ${resolvedWidth};
      margin-left: auto;
      margin-right: auto;
    `
      : `
      width: 100%;
      max-width: 100%;
      margin-left: auto;
      margin-right: auto;
    `;

  return `
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body {
      margin: 0;
      padding: ${resolvedPadding};
      font-family: 'Microsoft YaHei', sans-serif;
      -webkit-print-color-adjust: exact;
      print-color-adjust: exact;
      ${bodyHeightStyles}
    }

    .lodop-print-wrapper {
      ${wrapperWidthStyles}
      border-radius: 6px;
    }

    .lodop-print-wrapper *,
    .lodop-print-wrapper *::before,
    .lodop-print-wrapper *::after {
      max-width: 100%;
      box-sizing: border-box;
    }

    .lodop-print-wrapper table {
      width: 100% !important;
      border-collapse: collapse;
    }

    @media print {
      @page {
        size: ${options.pageSize} portrait;
        margin: ${options.margin};
      }

      html,
      body {
        margin: 0 !important;
        padding: 0 !important;
      }

      body {
        margin: 0;
        padding: ${resolvedPadding} !important;
      }

      .lodop-print-wrapper {
        ${wrapperWidthStyles}
      }

      h1, h2, h3, h4, h5, h6 {
        page-break-after: avoid;
        page-break-inside: avoid;
        break-after: avoid;
        break-inside: avoid;
      }

      table, figure, img {
        page-break-inside: avoid;
        break-inside: avoid;
      }

      tr {
        page-break-inside: avoid;
        break-inside: avoid;
      }

      .page-break,
      .print-page-break {
        page-break-after: always;
        break-after: page;
      }

      .page-break:last-child,
      .print-page-break:last-child {
        page-break-after: auto;
        break-after: auto;
      }

      .no-print {
        display: none !important;
      }
    }

    ${options.customStyles}
  `;
};

const buildThermalStyles = (
  options: ResolvedStyleOptions,
  resolvedPadding: string
): string => {
  const safeWidth = '76mm';

  return `
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    html,
    body {
      margin: 0;
      padding: 0;
    }

    body {
      padding: ${resolvedPadding};
      font-family: 'Microsoft YaHei', 'PingFang SC', sans-serif;
      font-size: 12px;
      -webkit-print-color-adjust: exact;
      print-color-adjust: exact;
      background: #fff;
    }

    .lodop-print-wrapper {
      width: ${safeWidth};
      max-width: ${safeWidth};
      margin: 0 auto;
      padding: 12px 8px 16px;
      background: #fff;
    }

    .lodop-print-wrapper *,
    .lodop-print-wrapper *::before,
    .lodop-print-wrapper *::after {
      max-width: 100%;
      box-sizing: border-box;
    }

    .lodop-print-wrapper table {
      width: 100% !important;
      border-collapse: collapse;
    }

    @media print {
      @page {
        size: ${options.pageSize} portrait;
        margin: ${options.margin};
      }

      html,
      body {
        margin: 0 !important;
        padding: 0 !important;
      }

      body {
        padding: ${resolvedPadding} !important;
      }

      .lodop-print-wrapper {
        width: ${safeWidth};
        max-width: ${safeWidth};
        margin: 0 auto;
      }
    }

    ${options.customStyles}
  `;
};

/**
 * 创建 A5 打印文档，参考 index.html 的 convertDocument
 */
const createA5Document = (
  contentHtml: string,
  padding: string,
  width?: string
): string => {
  const widthStyles = width
    ? `
      .lodop-print-wrapper {
        width: ${width};
        max-width: ${width};
        margin: 0 auto;
      }
    `
    : '';

  return `
    <!DOCTYPE html>
    <html lang="zh-CN">
      <head>
        <meta charset="UTF-8" />
        <title>LODOP 打印</title>
        <style>
          * { box-sizing: border-box; }
          body {
            margin: 0;
            padding: ${padding};
            font-family: 'Microsoft YaHei', 'PingFang SC', sans-serif;
            -webkit-print-color-adjust: exact;
            print-color-adjust: exact;
          }
          .lodop-print-wrapper {
            border-radius: 6px;
          }
          .lodop-print-wrapper * { max-width: 100%; }
          .lodop-print-wrapper table { width: 100%; border-collapse: collapse; }
          ${widthStyles}
        </style>
      </head>
      <body>
        <div class="lodop-print-wrapper">${contentHtml}</div>
      </body>
    </html>
  `;
};

/**
 * 创建 A80 热敏纸打印文档，完全参考 index.html 的 convertDocument
 */
const createA80Document = (contentHtml: string, padding: string): string => {
  // 完全按照 index.html 的方式：固定使用 76mm
  const width = '76mm';
  const widthStyles = `
    .print-wrapper {
      width: ${width};
      max-width: ${width};
      margin: 0 auto;
    }
  `;

  return `
    <!DOCTYPE html>
    <html lang="zh-CN">
      <head>
        <meta charset="UTF-8" />
        <title>LODOP 测试</title>
        <style>
          * { box-sizing: border-box; }
          body {
            margin: 0;
            padding: ${padding};
            font-family: 'Microsoft YaHei','PingFang SC',sans-serif;
            -webkit-print-color-adjust: exact;
            print-color-adjust: exact;
          }
          .print-wrapper {
            padding: 12px 5px 30px 5px;
            background: #fff;
          }
          .print-wrapper * { max-width: 100%; }
          .print-wrapper table { width: 100%; border-collapse: collapse; }
          /* 强制重置 .case-page 的所有样式，包括内联样式 */
          .print-wrapper .case-page,
          .print-wrapper .case-page[style] {
            max-width: 100% !important;
            width: 100% !important;
            margin: 0 !important;
            padding: 0 !important;
            box-sizing: border-box !important;
            /* 移除所有可能限制宽度的样式 */
            min-width: auto !important;
          }
          /* 确保 wrapper 内的所有元素都能正确填充 */
          .print-wrapper > * {
            width: 100% !important;
            max-width: 100% !important;
          }
          ${widthStyles}
        </style>
      </head>
      <body>
        <div class="print-wrapper">${contentHtml}</div>
      </body>
    </html>
  `;
};

const getLodopInstance = (): LodopInstance | null => {
  if (typeof window === 'undefined') return null;
  try {
    if (typeof window.getCLodop === 'function') {
      const lodop = window.getCLodop();
      if (lodop) return lodop;
    }
    if (window.CLODOP) {
      return window.CLODOP;
    }
  } catch (error) {
    console.error('获取 LODOP 实例失败:', error);
  }
  return null;
};

/**
 * 根据纸张类型自动选择打印机
 * @param lodop LODOP 实例
 * @param pageSize 纸张类型 'A5' | 'A80'
 * @returns 找到的打印机索引，未找到返回 -1
 */
const selectPrinterByPaperSize = (
  lodop: LodopInstance,
  pageSize: 'A5' | 'A80'
): number => {
  try {
    // 检查是否有打印机枚举相关 API
    if (
      typeof lodop.GET_PRINTER_COUNT !== 'function' ||
      typeof lodop.SET_PRINTER_INDEX !== 'function'
    ) {
      console.warn('LODOP 不支持打印机枚举功能，跳过自动选择');
      return -1;
    }

    const printerCount = lodop.GET_PRINTER_COUNT();
    if (printerCount <= 0) {
      console.warn('未找到可用打印机');
      return -1;
    }

    // 目标纸张配置
    const targetPaper = PAPER_SIZES[pageSize];
    const targetWidth = convertSizeToLodopValue(targetPaper.width);
    const targetHeight =
      targetPaper.height === 'auto'
        ? 0
        : convertSizeToLodopValue(targetPaper.height);
    const targetName = targetPaper.name;

    // 匹配策略：优先按名称匹配，其次按尺寸匹配
    const matchBySize = (width: number, height: number): boolean => {
      if (!targetWidth) return false;
      // 允许 5% 的误差
      const widthTolerance = targetWidth * 0.05;
      const widthMatch =
        Math.abs(width - targetWidth) <= widthTolerance ||
        Math.abs(width - targetWidth) <= 50; // 至少允许 5mm 误差

      if (targetHeight === 0) {
        // 热敏纸（高度为 0），只匹配宽度
        return widthMatch;
      }

      if (!height) return false;
      const heightTolerance = targetHeight * 0.05;
      const heightMatch =
        Math.abs(height - targetHeight) <= heightTolerance ||
        Math.abs(height - targetHeight) <= 50;

      return widthMatch && heightMatch;
    };

    // 遍历所有打印机
    for (let i = 0; i < printerCount; i++) {
      try {
        lodop.SET_PRINTER_INDEX(i);
        const printerName =
          typeof lodop.GET_PRINTER_NAME === 'function'
            ? lodop.GET_PRINTER_NAME(i)
            : `打印机${i + 1}`;

        // 忽略虚拟打印机（PDF打印机、XPS打印机等）
        const printerNameLower = printerName.toLowerCase();
        if (
          printerNameLower.includes('pdf') ||
          printerNameLower.includes('xps') ||
          printerNameLower.includes('onenote') ||
          printerNameLower.includes('fax') ||
          printerNameLower.includes('传真')
        ) {
          console.log(`跳过虚拟打印机: ${printerName}`);
          continue;
        }

        // 检查是否有纸张枚举 API
        if (typeof lodop.GET_PAGESIZES_COUNT !== 'function') {
          // 如果没有纸张枚举 API，尝试按打印机名称匹配
          // 热敏纸通常包含 "热敏"、"thermal"、"80mm" 等关键词
          if (pageSize === 'A80') {
            const nameLower = printerName.toLowerCase();
            if (
              nameLower.includes('热敏') ||
              nameLower.includes('thermal') ||
              nameLower.includes('80mm') ||
              nameLower.includes('80')
            ) {
              console.log(`根据打印机名称匹配到: ${printerName}`);
              return i;
            }
          }
          continue;
        }

        const pageSizeCount = lodop.GET_PAGESIZES_COUNT(i);
        if (pageSizeCount <= 0) continue;

        // 遍历该打印机的所有纸张
        for (let j = 0; j < pageSizeCount; j++) {
          try {
            const pageName =
              typeof lodop.GET_PAGESIZES_NAME === 'function'
                ? lodop.GET_PAGESIZES_NAME(i, j)
                : '';
            const pageWidth =
              typeof lodop.GET_PAGESIZES_WIDTH === 'function'
                ? lodop.GET_PAGESIZES_WIDTH(i, j)
                : 0;
            const pageHeight =
              typeof lodop.GET_PAGESIZES_HEIGHT === 'function'
                ? lodop.GET_PAGESIZES_HEIGHT(i, j)
                : 0;

            // 策略1：按名称匹配（精确或包含）
            if (pageName) {
              const nameUpper = pageName.toUpperCase();
              if (
                nameUpper === targetName ||
                nameUpper.includes(targetName) ||
                (pageSize === 'A80' &&
                  (nameUpper.includes('80') ||
                    nameUpper.includes('热敏') ||
                    nameUpper.includes('THERMAL')))
              ) {
                console.log(
                  `根据纸张名称匹配到打印机: ${printerName}, 纸张: ${pageName}`
                );
                return i;
              }
            }

            // 策略2：按尺寸匹配
            if (matchBySize(pageWidth, pageHeight)) {
              console.log(
                `根据纸张尺寸匹配到打印机: ${printerName}, 纸张: ${pageName || '未知'}, 尺寸: ${pageWidth}x${pageHeight}`
              );
              return i;
            }
          } catch (error) {
            // 忽略单个纸张查询错误，继续下一个
            continue;
          }
        }
      } catch (error) {
        // 忽略单个打印机查询错误，继续下一个
        console.warn(`查询打印机 ${i} 时出错:`, error);
        continue;
      }
    }

    console.warn(`未找到支持 ${targetName} 纸张的打印机`);
    return -1;
  } catch (error) {
    console.error('选择打印机时出错:', error);
    return -1;
  }
};

/**
 * A5 打印，参考 index.html 的 handlePrint
 */
const printA5WithLodop = (
  lodop: LodopInstance,
  documentHtml: string,
  config: PrintConfig,
  options: ResolvedStyleOptions,
  isPreview: boolean
): boolean => {
  try {
    const title = config.title || '打印文档';
    lodop.PRINT_INIT(title);
    if (typeof lodop.SET_PRINT_MODE === 'function') {
      lodop.SET_PRINT_MODE('AUTO_CLOSE_PREWINDOW', true);
      lodop.SET_PRINT_MODE('FULL_WIDTH_FOR_OVERFLOW', true);
    }

    // 根据纸张类型自动选择打印机
    if (
      !config.printer?.disableAutoSelect &&
      typeof lodop.SET_PRINTER_INDEX === 'function'
    ) {
      const printerIndex =
        config.printer?.index !== undefined
          ? config.printer.index
          : selectPrinterByPaperSize(lodop, 'A5');
      if (printerIndex >= 0) {
        lodop.SET_PRINTER_INDEX(printerIndex);
      }
    }

    const preset = PAPER_SIZES[options.pageSize];
    const pageWidth = preset.width;
    const pageHeight = preset.height;
    const marginValues = parseMarginValues(options.margin);

    lodop.SET_PRINT_PAGESIZE(
      1, // 纵向
      convertSizeToLodopValue(pageWidth),
      convertSizeToLodopValue(pageHeight),
      preset.name
    );

    lodop.ADD_PRINT_HTM(
      marginValues.top,
      marginValues.left,
      `RightMargin:${marginValues.right}`,
      `BottomMargin:${marginValues.bottom}`,
      documentHtml
    );

    if (isPreview) {
      if (typeof lodop.PREVIEW === 'function') {
        lodop.PREVIEW();
        return true;
      }
      return false;
    }

    if (typeof lodop.PRINT === 'function') {
      lodop.PRINT();
      return true;
    }
    return false;
  } catch (error) {
    console.error('LODOP A5 打印失败:', error);
    return false;
  }
};

/**
 * A80 热敏纸打印，参考 index.html 的 handleThermalPrint
 */
const printA80WithLodop = (
  lodop: LodopInstance,
  documentHtml: string,
  config: PrintConfig,
  options: ResolvedStyleOptions,
  isPreview: boolean
): boolean => {
  try {
    const title = config.title || '打印文档';
    lodop.PRINT_INIT(title);
    if (typeof lodop.SET_PRINT_MODE === 'function') {
      lodop.SET_PRINT_MODE('AUTO_CLOSE_PREWINDOW', true);
      lodop.SET_PRINT_MODE('FULL_WIDTH_FOR_OVERFLOW', true);
    }

    // 根据纸张类型自动选择打印机（优先选择热敏打印机）
    if (
      !config.printer?.disableAutoSelect &&
      typeof lodop.SET_PRINTER_INDEX === 'function'
    ) {
      const printerIndex =
        config.printer?.index !== undefined
          ? config.printer.index
          : selectPrinterByPaperSize(lodop, 'A80');
      if (printerIndex >= 0) {
        lodop.SET_PRINTER_INDEX(printerIndex);
      }
    }

    const preset = PAPER_SIZES[options.pageSize];
    const marginValues = parseMarginValues(options.margin);

    lodop.SET_PRINT_PAGESIZE(
      1, // 纵向（必须用 1，不能用 3）
      convertSizeToLodopValue(preset.width),
      0, // 热敏纸高度为 0
      preset.name
    );

    lodop.ADD_PRINT_HTM(
      marginValues.top,
      marginValues.left,
      `RightMargin:${marginValues.right}`,
      `BottomMargin:${marginValues.bottom}`,
      documentHtml
    );

    if (isPreview) {
      if (typeof lodop.PREVIEW === 'function') {
        lodop.PREVIEW();
        return true;
      }
      return false;
    }

    if (typeof lodop.PRINT === 'function') {
      lodop.PRINT();
      return true;
    }
    return false;
  } catch (error) {
    console.error('LODOP A80 打印失败:', error);
    return false;
  }
};

const printWithBrowser = (
  documentHtml: string,
  config: PrintConfig,
  resolve: (value: boolean) => void
): void => {
  const iframe = document.createElement('iframe');
  iframe.style.position = 'fixed';
  iframe.style.top = '-10000px';
  iframe.style.left = '-10000px';
  iframe.style.width = '0';
  iframe.style.height = '0';
  iframe.style.border = 'none';

  document.body.appendChild(iframe);
  const iframeWindow = iframe.contentWindow;
  const iframeDoc = iframeWindow?.document;

  if (!iframeWindow || !iframeDoc) {
    console.error('无法创建打印 iframe');
    if (iframe.parentNode) {
      document.body.removeChild(iframe);
    }
    resolve(false);
    return;
  }

  iframeDoc.open();
  iframeDoc.write(documentHtml);
  iframeDoc.close();

  const handlePrint = () => {
    try {
      iframeWindow.focus();
      iframeWindow.print();

      const removeDelay = config.removeDelay ?? 500;
      setTimeout(() => {
        try {
          if (iframe.parentNode) {
            document.body.removeChild(iframe);
          }
          config.onAfterPrint?.();
          resolve(true);
        } catch (error) {
          console.error('移除 iframe 失败:', error);
          resolve(true);
        }
      }, removeDelay);
    } catch (error) {
      console.error('浏览器打印失败:', error);
      if (iframe.parentNode) {
        document.body.removeChild(iframe);
      }
      resolve(false);
    }
  };

  if (iframeWindow.document.readyState === 'complete') {
    setTimeout(handlePrint, 100);
  } else {
    iframe.onload = handlePrint;
  }
};

const getPrintContent = (config: PrintConfig): string => {
  if (typeof config.content === 'string') {
    return config.content;
  }
  if (config.content instanceof HTMLElement) {
    return config.content.innerHTML;
  }
  return '';
};

const executePrint = async (
  config: PrintConfig,
  isPreview: boolean
): Promise<boolean> => {
  if (typeof window === 'undefined') {
    console.error('打印功能只能在浏览器环境中使用');
    return false;
  }

  return new Promise((resolve) => {
    try {
      config.onBeforePrint?.();

      const contentHtml = getPrintContent(config);
      const options = resolveStyleOptions(config);
      const isA80 = options.pageSize === 'A80';

      let documentHtml: string;
      if (isA80) {
        // A80 热敏纸：固定 76mm 宽度，完全参考 index.html
        const padding = options.resolvedPadding;
        documentHtml = createA80Document(contentHtml, padding);
      } else {
        // A5：使用计算出的宽度
        const padding = options.resolvedPadding;
        const width = options.resolvedWidth;
        documentHtml = createA5Document(contentHtml, padding, width);
      }

      const lodop = getLodopInstance();
      if (lodop) {
        const lodopResult = isA80
          ? printA80WithLodop(lodop, documentHtml, config, options, isPreview)
          : printA5WithLodop(lodop, documentHtml, config, options, isPreview);

        if (lodopResult) {
          config.onAfterPrint?.();
          resolve(true);
          return;
        }
        console.warn('LODOP 打印失败，尝试使用浏览器打印');
      }

      printWithBrowser(documentHtml, config, resolve);
    } catch (error) {
      console.error('执行打印失败:', error);
      resolve(false);
    }
  });
};

export const printPreview = async (config: PrintConfig): Promise<boolean> => {
  return await executePrint(config, true);
};

export const printDirect = async (config: PrintConfig): Promise<boolean> => {
  return await executePrint(config, false);
};

export const printCommon = async (
  config: PrintConfig,
  isPreview: boolean = false
): Promise<boolean> => {
  return isPreview ? await printPreview(config) : await printDirect(config);
};

export const printElement = async (
  element: HTMLElement | string,
  options: Omit<PrintConfig, 'content'> = {}
): Promise<boolean> => {
  let targetElement: HTMLElement | null = null;

  if (typeof element === 'string') {
    targetElement = document.querySelector(element);
    if (!targetElement) {
      console.error(`未找到元素: ${element}`);
      return false;
    }
  } else {
    targetElement = element;
  }

  return await printCommon({
    ...options,
    content: targetElement,
  });
};

export const printHtml = async (
  html: string,
  options: Omit<PrintConfig, 'content'> = {}
): Promise<boolean> => {
  return await printCommon({
    ...options,
    content: html,
  });
};

/** Batch printing configuration */
export interface BatchPrintConfig {
  printConfigs: PrintConfig[];
  delayBetweenPrints?: number;
  onProgress?: (current: number, total: number, config: PrintConfig) => void;
  onComplete?: (successCount: number, failCount: number) => void;
  continueOnError?: boolean;
}

export interface BatchPrintResult {
  total: number;
  successCount: number;
  failCount: number;
  results: Array<{
    index: number;
    success: boolean;
    config: PrintConfig;
    error?: any;
  }>;
}

export const printMultiple = async (
  batchConfig: BatchPrintConfig
): Promise<BatchPrintResult> => {
  const {
    printConfigs,
    delayBetweenPrints = 1000,
    onProgress,
    onComplete,
    continueOnError = true,
  } = batchConfig;

  const results: BatchPrintResult['results'] = [];
  let successCount = 0;
  let failCount = 0;

  for (let i = 0; i < printConfigs.length; i++) {
    const currentConfig = printConfigs[i];
    onProgress?.(i + 1, printConfigs.length, currentConfig!);

    try {
      const success = await printDirect(currentConfig!);
      if (success) {
        successCount++;
      } else {
        failCount++;
        if (!continueOnError) {
          results.push({
            index: i,
            success: false,
            config: currentConfig!,
            error: '打印失败',
          });
          break;
        }
      }

      results.push({
        index: i,
        success,
        config: currentConfig!,
      });
    } catch (error) {
      failCount++;
      results.push({
        index: i,
        success: false,
        config: currentConfig!,
        error,
      });
      if (!continueOnError) {
        break;
      }
    }

    if (i < printConfigs.length - 1 && delayBetweenPrints > 0) {
      await new Promise((resolve) => setTimeout(resolve, delayBetweenPrints));
    }
  }

  onComplete?.(successCount, failCount);

  return {
    total: printConfigs.length,
    successCount,
    failCount,
    results,
  };
};

export const printHtmlArray = async (
  htmlArray: string[],
  commonOptions: Omit<PrintConfig, 'content'> = {},
  batchOptions: Omit<BatchPrintConfig, 'printConfigs'> = {}
): Promise<BatchPrintResult> => {
  const printConfigs: PrintConfig[] = htmlArray.map((html) => ({
    ...commonOptions,
    content: html,
  }));

  return await printMultiple({
    ...batchOptions,
    printConfigs,
  });
};

export interface MergedPrintConfig {
  htmlArray: string[];
  options?: Omit<PrintConfig, 'content'>;
  pageWrapperClass?: string;
  autoAddPageBreak?: boolean;
}

export const printMergedPages = async (
  config: MergedPrintConfig
): Promise<boolean> => {
  const {
    htmlArray,
    options = {},
    pageWrapperClass = 'print-page-break',
    autoAddPageBreak = true,
  } = config;

  if (!htmlArray || htmlArray.length === 0) {
    console.error('HTML 内容数组不能为空');
    return false;
  }

  const mergedHtml = htmlArray
    .map((html, index) => {
      const isLast = index === htmlArray.length - 1;
      const breakClass = autoAddPageBreak && !isLast ? pageWrapperClass : '';
      return `<div class="${breakClass}">${html}</div>`;
    })
    .join('\n');

  return await printHtml(mergedHtml, options);
};

export const printMergedElements = async (
  elements: (HTMLElement | string)[],
  config: Omit<MergedPrintConfig, 'htmlArray'> = {}
): Promise<boolean> => {
  const htmlArray: string[] = [];

  for (const element of elements) {
    let targetElement: HTMLElement | null = null;

    if (typeof element === 'string') {
      targetElement = document.querySelector(element);
      if (!targetElement) {
        console.error(`未找到元素: ${element}`);
        continue;
      }
    } else {
      targetElement = element;
    }

    htmlArray.push(targetElement.innerHTML);
  }

  if (htmlArray.length === 0) {
    console.error('未找到任何可以打印的元素');
    return false;
  }

  return await printMergedPages({
    ...config,
    htmlArray,
  });
};

/**
 * 打印机信息接口
 */
export interface PrinterInfo {
  index: number;
  name: string;
  pageSizes: Array<{
    name: string;
    width: number;
    height: number;
  }>;
}

/**
 * 获取所有打印机列表及其支持的纸张
 * @returns 打印机信息数组
 */
export const getPrinterList = (): PrinterInfo[] => {
  const lodop = getLodopInstance();
  if (!lodop) {
    console.warn('LODOP 未初始化');
    return [];
  }

  try {
    if (
      typeof lodop.GET_PRINTER_COUNT !== 'function' ||
      typeof lodop.SET_PRINTER_INDEX !== 'function'
    ) {
      console.warn('LODOP 不支持打印机枚举功能');
      return [];
    }

    const printerCount = lodop.GET_PRINTER_COUNT();
    if (printerCount <= 0) {
      return [];
    }

    const printers: PrinterInfo[] = [];

    for (let i = 0; i < printerCount; i++) {
      try {
        lodop.SET_PRINTER_INDEX(i);
        const printerName =
          typeof lodop.GET_PRINTER_NAME === 'function'
            ? lodop.GET_PRINTER_NAME(i)
            : `打印机${i + 1}`;

        const pageSizes: PrinterInfo['pageSizes'] = [];

        if (typeof lodop.GET_PAGESIZES_COUNT === 'function') {
          const pageSizeCount = lodop.GET_PAGESIZES_COUNT(i);
          for (let j = 0; j < pageSizeCount; j++) {
            try {
              const pageName =
                typeof lodop.GET_PAGESIZES_NAME === 'function'
                  ? lodop.GET_PAGESIZES_NAME(i, j)
                  : '';
              const pageWidth =
                typeof lodop.GET_PAGESIZES_WIDTH === 'function'
                  ? lodop.GET_PAGESIZES_WIDTH(i, j)
                  : 0;
              const pageHeight =
                typeof lodop.GET_PAGESIZES_HEIGHT === 'function'
                  ? lodop.GET_PAGESIZES_HEIGHT(i, j)
                  : 0;

              pageSizes.push({
                name: pageName,
                width: pageWidth,
                height: pageHeight,
              });
            } catch (error) {
              // 忽略单个纸张查询错误
              continue;
            }
          }
        }

        printers.push({
          index: i,
          name: printerName,
          pageSizes,
        });
      } catch (error) {
        console.warn(`获取打印机 ${i} 信息时出错:`, error);
        continue;
      }
    }

    return printers;
  } catch (error) {
    console.error('获取打印机列表失败:', error);
    return [];
  }
};
